home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / exampleCode / opengl / xlib / tabletogl.c < prev    next >
C/C++ Source or Header  |  1996-11-11  |  24KB  |  643 lines

  1. /*
  2.  * Copyright (c) 1993-94, Silicon Graphics, Inc.
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and
  5.  * its documentation for any purpose is hereby granted without fee, provided
  6.  * that the name of Silicon Graphics may not be used in any advertising or
  7.  * publicity relating to the software without the specific, prior written
  8.  * permission of Silicon Graphics.
  9.  *
  10.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
  11.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
  12.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  13.  *
  14.  * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
  15.  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
  16.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE
  17.  * POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN
  18.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  19.  *
  20.  * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
  21.  */
  22. /*
  23.  * tabletogl.c :  an openGL-Xlib tablet "line-drawing" demo program.  
  24.  *                This is the "after" version, ported from its 4.0 
  25.  *                GLX mixed model "before" counterpart, located at 
  26.  *                ../../GLX/tablet/tabletglx.c
  27.  *
  28.  *                tabletogl imitates a pen (stylus) drawing on a surface:
  29.  *                while the pen (stylus' button) is pressed down, a line
  30.  *                continues to be drawn.  when the pen is released, the 
  31.  *                current line stops.  
  32.  *
  33.  *   There are a function prior to the infinite loop worth noting:
  34.  *
  35.  *       setupdevs() finds, opens, and creates a handle to the "tablet" 
  36.  *       device structure.  it then determines the given type and class 
  37.  *       of each device event we're going to be interested in, and then 
  38.  *       makes requests to the server to send us events that match the 
  39.  *       events and devices described by the event list *and* that come 
  40.  *       from our specific window.
  41.  *
  42.  *    Following this, the get/process input infinite loop occupies the
  43.  *    rest of the program's energies.  the core of this is the "default"
  44.  *    portion of the "switch (event.type)" statement which catches the
  45.  *    tablet events being generated.  notice this is where the
  46.  *    {tablet_motion_type, tablet_press_type, tablet_release_type} vars 
  47.  *    come into play:  recall these were defined in setupdevs() with the 
  48.  *    3 macros DeviceMotionNotify, DeviceButtonPress, and 
  49.  *    DeviceButtonRelease, respectively.  XSelectExtensionEvent then was 
  50.  *    used to ask the server to send us any events generated by these 
  51.  *    devices in our window.
  52.  
  53.  *                                     ratmandu -- ported to openGL, aug 93
  54.  */
  55. #include <stdio.h>
  56. #include <stdlib.h>
  57. #include <GL/gl.h>
  58. #include <GL/glx.h>
  59. #include <GL/glu.h>
  60. #include <X11/Xlib.h>
  61. #include <X11/Xutil.h>
  62. #include <X11/Xos.h>
  63. #include <X11/Xatom.h>
  64. #include <X11/extensions/XI.h>
  65. #include <X11/extensions/XInput.h>
  66.  
  67. #define YELLOW 3
  68. #define BLUE   4
  69. #define CYAN   6
  70.  
  71. #define X 0
  72. #define Y 1
  73. #define MAXRESOLUTION 2206
  74.  
  75.    /* line drawing structures to create a new linked-list everytime the
  76.     * stylus (button) is pressed down and grow that list as long as
  77.     * MotionNotify events occur.  when the stylus (button) is released,
  78.     * free up the list and reset the head and tail to point to null
  79.     */
  80. #define newll()  ((struct lineElement *)malloc(sizeof(struct lineElement)))
  81.  
  82. struct lineElement {
  83.     long xy[2];
  84.     struct lineElement *next;
  85. };
  86.  
  87. typedef struct {
  88.     struct lineElement *head, *tail;
  89. } LineList;
  90.  
  91. LineList lineLs;
  92. struct lineElement *lineDummy;
  93.  
  94. Display *dpy;                                    /* The X server connection */
  95. Atom del_atom;                                   /* WM_DELETE_WINDOW atom   */
  96. Window glwin;                                    /* handle to the GL window */
  97.  
  98. static void openwindow(char *);
  99. static void setupdevs(void);
  100. static void makeframe(void);
  101. static void drawcurrentline(void);
  102. static void clean_exit(void);
  103. static void makeRasterFont(Display **dpy);
  104. static void printString(char *s);
  105.  
  106. int tablet_device_id;                            /* device handles for the  */
  107. int tablet_press_type;      /* the following 3 tablet device ID handles are */
  108. int tablet_release_type;    /* defined in setupdevs() and then used in the  */
  109. int tablet_motion_type;     /* infinite (get/process input) loop in main    */
  110.  
  111. float ratio;         /* stores the current ratio to scale the tablet's full */
  112.                      /* range of coordinates into the window's current size */
  113. int xsize, ysize;                    /* stores window's current size values */
  114. XEvent event;
  115.  
  116.  
  117.  
  118. void main(int argc, char *argv[])
  119. {
  120.     int i;
  121.     long xprev, yprev; /* used if either the x or y stylus val doesn't chng */
  122.     int myExpose, myConfigure, myMotion,
  123.         myButtPress, myButtRelease, myButtDown; /* store which events occur */
  124.  
  125.  
  126.  
  127.     myExpose = myConfigure = myMotion = GL_FALSE;
  128.     myButtPress = myButtRelease = myButtDown = GL_FALSE;
  129.  
  130.     openwindow(argv[0]);     /* open "window" something like winopen wud do */
  131.     setupdevs();            /* make the necessary connections to the tablet */
  132.     makeRasterFont(&dpy);                                      /* make font */
  133.  
  134.     /*
  135.      * The event loop. 
  136.      */
  137.     while (1) {          /* standard logic:  get event(s), process event(s) */
  138.  
  139.         int axis_data[6];
  140.  
  141.         glFlush();                            /* For proper DGL performance */
  142.  
  143.     /* this "do while" loop does the `get events' half of the "get events,
  144.      *  process events" action of the infinite while.  this is to ensure
  145.      *  the event queue is always drained before the events that have come
  146.      *  in are processed.
  147.      */
  148.         do {
  149.  
  150.             XNextEvent(dpy, &event);
  151.                 switch (event.type) {
  152.  
  153.             /* "Expose" events are sort of like "REDRAW" in gl-speak in
  154.              *  terms of when a window becomes visible, or a previously
  155.              *  invisible part becomes visible.
  156.              */
  157.                 case Expose:                                   /* Exposures */
  158.                     myExpose = GL_TRUE;
  159.                     break;
  160.  
  161.  
  162.             /* "ConfigNotify" events are like "REDRAW" in terms of changes
  163.              *   to a window's size or position.
  164.              */
  165.                 case ConfigureNotify:                 /* Resize GL manually */
  166.             /* save the changed width/height of the parent X window */
  167.                     xsize = event.xconfigure.width;
  168.                     ysize = event.xconfigure.height;
  169.                     ratio  = (float) xsize / MAXRESOLUTION;
  170.                     myConfigure = GL_TRUE;
  171.                     break;
  172.  
  173.                 case ButtonRelease:                       /* Back door exit */
  174.                     if (event.xbutton.button == Button1)
  175.                         clean_exit();
  176.                     break;
  177.  
  178.                 case ClientMessage:                      /* WM invoked exit */
  179.                     if (event.xclient.data.l[0] == del_atom)
  180.                         clean_exit();
  181.                     break;
  182.  
  183.                 /* since interest is on the tablet, it becomes the default */
  184.                 default:   
  185.  
  186.                     if ((lineLs.tail != NULL) &&  /* make sure we've already
  187.                                                     processed a button (stylus)
  188.                                                     press event which sets up
  189.                                                     the linked-list for x/y 
  190.                                                     pair storage/line drawing */
  191.  
  192.                         (event.type == tablet_motion_type) &&  /* make sure
  193.                                                                  this is a mo-
  194.                                                                  tion event */
  195.  
  196.                          myButtDown) {  /* and make sure button itself is still
  197.                                            down--myButtPress only processes the
  198.                                            occurence of the but press (which 
  199.                                            sets up the new linked list) and 
  200.                                            then is immediately reset to FALSE */
  201.  
  202.                 /* the body of this if statement processes "Motion" events
  203.                  *  from any one of the dials.  the axes_count element of 
  204.                  *  the XDeviceMotionEvent structure (defined in /usr/include
  205.                  *  /X11/extensions/XInput.h) is used to determine if there 
  206.                  *  are 2 or only 1 new coordinate value(s):
  207.                  *  if (axes_count == 2), both X and Y have changed, 
  208.                  *  if (axes_count == 1), only Y has changed--X has not, and
  209.                  *  if (axes_count == 0), only X has changed--Y has not. 
  210.                  */
  211.                         XDeviceMotionEvent *M = (XDeviceMotionEvent *) &event;
  212.  
  213.                         if (M->axes_count != 2) {  /* if x OR y didn't chng */
  214.                             xprev = lineLs.tail->xy[X];/* axes_count < 2 so */
  215.                             yprev = lineLs.tail->xy[Y];/* need to save prev */
  216.                         }
  217.                         lineDummy       = newll();   /* alloc a new element */
  218.                         lineDummy->next = NULL;      /* for current line    */
  219.                         lineLs.tail->next = lineDummy;  /* point tail to it */
  220.                         lineLs.tail       = lineDummy;
  221.  
  222.                         if (M->axes_count == 2) {       /* if new x/y pair, */
  223.  
  224.                             lineLs.tail->xy[X] = M->axis_data[X];
  225.                             lineLs.tail->xy[Y] = M->axis_data[Y];
  226.  
  227.                         } else if (M->first_axis == 0) {/* elseif new X val */
  228.  
  229.                             lineLs.tail->xy[X] = M->axis_data[0];
  230.                             lineLs.tail->xy[Y] = yprev;
  231.  
  232.                         } else if (M->first_axis == 1) {/* elseif new Y val */
  233.  
  234.                             lineLs.tail->xy[X] = xprev;
  235.                             lineLs.tail->xy[Y] = M->axis_data[0];
  236.  
  237.                         }
  238.                         myMotion = GL_TRUE;
  239.                         
  240.                     } else if (event.type == tablet_press_type) {
  241.  
  242.                         XDeviceButtonEvent *P = (XDeviceButtonEvent *) &event;
  243.  
  244.                         xprev = P->axis_data[0]; /* butt's been pressed so  */
  245.                         yprev = P->axis_data[1]; /* now start to make a new */
  246.                         myButtPress = GL_TRUE;   /* line.  this cur pnt'll  */
  247.                         myButtDown = GL_TRUE;    /* be the "move to" coord  */
  248.  
  249.                     } else if (event.type == tablet_release_type) {
  250.  
  251.                         myButtRelease = GL_TRUE;
  252.                         myButtDown = GL_FALSE;
  253.                     }
  254.                     break;
  255.  
  256.             }  /* end switch (event.type) */
  257.  
  258.         } while (XPending(dpy));   /* end "do { } while".
  259.                                     * XPending() is like qtest()--it only
  260.                                     * tells you if there're any events
  261.                                     * presently in the queue.  it does not
  262.                                     * disturb queue's contents in any way.
  263.                                     */
  264.         
  265.     /* On an "Expose" event, redraw the affected window
  266.      */
  267.         if (myExpose) {
  268.             makeframe();                               /* draw the GL stuff */
  269.             myExpose = GL_FALSE;             /* reset flag--queue now empty */
  270.         }
  271.  
  272.     /* On a "ConfigureNotify" event, resize window (XMoveResizeWindow),
  273.      *  and then redraw contents.
  274.      */
  275.         if (myConfigure) {
  276.             glViewport(0, 0, xsize-1, ysize-1);
  277.             makeframe();
  278.             myConfigure = GL_FALSE;          /* reset flag--queue now empty */
  279.         }
  280.  
  281.     /* a motion-type event (the next x/y pair was already saved up above) 
  282.      *  means we're still drawing more along the current line.
  283.      */
  284.         if (myMotion) {
  285.             drawcurrentline();     /* butt still pressed, pen still moving, */
  286.                                    /* keep drawing at end of current line   */
  287.             myMotion = GL_FALSE;             /* reset flag--queue now empty */
  288.         }
  289.  
  290.     /* a "button press"-type event means we're starting a new line so we
  291.      *  need to re-initialize/create our linked-list.
  292.      */
  293.         if (myButtPress) {
  294.             XDeviceButtonEvent *B = (XDeviceButtonEvent *) &event;
  295.  
  296.             lineDummy       = newll();    /* making a new line so start a   */
  297.             lineDummy->next = NULL;       /* new list.  point head and tail */
  298.             lineLs.head = lineDummy;      /* to it, and assign current new  */
  299.             lineLs.tail = lineDummy;      /* point to "tail" of list        */
  300.             lineLs.tail->xy[X] = xprev;   /* make our first point be what   */
  301.             lineLs.tail->xy[Y] = yprev;   /* we saved up above              */
  302.             myButtPress = GL_FALSE;          /* reset flag--queue now empty */
  303.         }
  304.  
  305.     /* a "button release"-type event means the current line is complete
  306.      *  so now we need to free up the current linked-list.
  307.      */
  308.         if (myButtRelease) {
  309.             struct lineElement *ptr;
  310.             for (ptr = lineLs.head; ptr->next != NULL; ptr = ptr->next) {
  311.                 free(ptr);                   /* "empty" our current list    */
  312.             }
  313.             lineLs.head = NULL;
  314.             lineLs.tail = NULL;
  315.             myButtRelease = GL_FALSE;        /* reset flag--queue now empty */
  316.         }
  317.     }
  318. }
  319.  
  320.  
  321. static int attributeList[] = { None };   /* use the default graphics visual */
  322.  
  323.  
  324. /* WaitForNotify:
  325.  *   used to make sure the MapWindow() calls inside openwindow() occur
  326.  *   beFORE glXMakeCurrent() is invoked so as to avoid a race condition.
  327.  */
  328. static Bool WaitForNotify(Display *d, XEvent *e, char *arg) {
  329.     return (e->type == MapNotify) && (e->xmap.window == (Window)arg);
  330. }
  331.  
  332.  
  333. /*  openwindow -
  334.  *     establish connection to X server, get screen info, specify the
  335.  *     attributes we want the WM to try to provide, and create the GL window
  336.  */
  337. static void openwindow(char *progname) {
  338.  
  339.     int scrnnum;                             /* X screen number            */
  340.     int xorig, yorig;                        /* window (upper-left) origin */
  341.     long scrnheight;
  342.     XSizeHints Winhints;                        /* used to fix window size */
  343.     Colormap cmap;
  344.     GLXContext cx;
  345.     XVisualInfo *vi;
  346.     XSetWindowAttributes swa;
  347.     XColor colorstruct;
  348.  
  349.  
  350.    /* Connect to the X server and get screen info */
  351.     if ((dpy = XOpenDisplay(NULL)) == NULL) {
  352.         fprintf(stderr, "%s: cannot connect to X server %s\n",
  353.                                  progname, XDisplayName(NULL));
  354.         exit(1);
  355.     }
  356.     scrnnum = DefaultScreen(dpy);
  357.     scrnheight = DisplayHeight(dpy, scrnnum);
  358.  
  359.    /* define window (upper-left) origin coords */
  360.     xorig = 0;
  361.     yorig = 0;
  362.     xsize = 500;
  363.     ysize = 500;
  364.  
  365.     ratio = (float) xsize / MAXRESOLUTION;   /* calculate ratio to scale 
  366.                                                 full tablet into window */
  367.  
  368.     /* get an appropriate visual */
  369.     vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributeList);
  370.     if (vi == NULL) {
  371.         printf("Couldn't get default visual (???)\n");
  372.         exit(0);
  373.     }
  374.  
  375.     /* create a GLX context */
  376.     cx = glXCreateContext(dpy, vi, NULL, GL_TRUE);
  377.     if (cx == NULL) {
  378.         printf("Couldn't get context.\n");
  379.         exit(0);
  380.     }
  381.  
  382.     /* create a colormap */
  383.     cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
  384.                            vi->visual, AllocAll);
  385.     /* create a window */
  386.     swa.colormap = cmap;
  387.     swa.border_pixel = 0;
  388.  
  389.     /* express interest in certain events */
  390.     swa.event_mask = StructureNotifyMask | ButtonPressMask |
  391.                        ButtonReleaseMask | ExposureMask;
  392.     glwin = XCreateWindow(dpy, RootWindow(dpy, vi->screen),
  393.                           xorig, yorig, xsize, ysize,
  394.                           0, vi->depth, InputOutput, vi->visual,
  395.                           CWBorderPixel|CWColormap|CWEventMask, &swa);
  396.  
  397.     XMapWindow(dpy, glwin);
  398.     XIfEvent(dpy, &event, WaitForNotify, (char*)glwin);
  399.  
  400.     XSync(dpy, GL_FALSE);
  401.     /* connect the context to the window */
  402.     if (!glXMakeCurrent(dpy, glwin, cx) == GL_TRUE) {
  403.         fprintf(stderr, "error w/glXMakeCurrent:  cudn't set");
  404.         fprintf(stderr, " context to the singlebuffered GL window\n");
  405.         exit(-1);
  406.     }
  407.  
  408.    /* specify the values for the Window Size Hints we want to enforce:  this
  409.     *  window's aspect ratio needs to stay at 1:1, constrain min and max
  410.     *  window size, and specify the initial origin and size of the window.
  411.     */
  412.     Winhints.x = xorig;         /* specify desired upper-left corner origin */
  413.     Winhints.y = yorig;         /* of window so prog will place itself      */
  414.     Winhints.width  = xsize;          /* specify desired x/y size of window */
  415.     Winhints.height = ysize;
  416.     Winhints.min_width = xsize/4;                     /* define min and max */
  417.     Winhints.max_width = scrnheight-1;                /* width and height   */
  418.     Winhints.min_height = ysize/4;
  419.     Winhints.max_height = scrnheight-1;
  420.     Winhints.min_aspect.x = 1;                /* keep aspect at a 1:1 ratio */
  421.     Winhints.max_aspect.x = 1;
  422.     Winhints.min_aspect.y = 1;
  423.     Winhints.max_aspect.y = 1;
  424.                                              /* set the corresponding flags */
  425.     Winhints.flags = USPosition|USSize|PMaxSize|PMinSize|PAspect;
  426.     XSetNormalHints(dpy, glwin, &Winhints);
  427.  
  428.    /* define string that will show up in the window title bar (and icon) */
  429.     XStoreName(dpy, glwin, "opengl tablet \"line drawing\" program");
  430.  
  431.    /* declare  interest in events we want the window to process */
  432.     XSelectInput(dpy, glwin, StructureNotifyMask | ExposureMask |
  433.                               ButtonPressMask | ButtonReleaseMask);
  434.  
  435.     XSetWMColormapWindows(dpy, glwin, &glwin, 1);
  436.  
  437.    /* express interest in WM killing this app */
  438.     if ((del_atom = XInternAtom(dpy, "WM_DELETE_WINDOW", GL_TRUE)) != None)
  439.         XSetWMProtocols(dpy, glwin, &del_atom, 1);
  440.  
  441.     colorstruct.pixel = YELLOW;
  442.     colorstruct.red   = 65535;
  443.     colorstruct.green = 65535;
  444.     colorstruct.blue  = 0;
  445.     colorstruct.flags = DoRed | DoGreen | DoBlue;
  446.     XStoreColor(dpy, cmap, &colorstruct);
  447.     colorstruct.pixel = BLUE;
  448.     colorstruct.red   = 0;
  449.     colorstruct.green = 0;
  450.     colorstruct.blue  = 35535;
  451.     colorstruct.flags = DoRed | DoGreen | DoBlue;
  452.     XStoreColor(dpy, cmap, &colorstruct);
  453.     colorstruct.pixel = CYAN;
  454.     colorstruct.red   = 0;
  455.     colorstruct.green = 65535;
  456.     colorstruct.blue  = 65535;
  457.     colorstruct.flags = DoRed | DoGreen | DoBlue;
  458.     XStoreColor(dpy, cmap, &colorstruct);
  459.  
  460.     glLineWidth(3.0);
  461.     glFlush();
  462. }
  463.  
  464.  
  465. /*  setupdevs - 
  466.  *
  467.  *   establish a live connection to the tablet device.
  468.  *
  469.  *   leverages off the "X11 Input Extension Library Specification" 
  470.  *   document (you *shud* be able to locate the on-line public access
  471.  *   directory which contains all the files to print hard-copy of this
  472.  *   document under .../mit/doc/extensions/xinput).  refer to
  473.  *   /usr/include/X11/extensions/{XI.h, XInput.h} for structures accessed.
  474.  */
  475. static void setupdevs() {
  476.  
  477.     int i, ndevices;
  478.     XDevice *tablet_device;
  479.     XDeviceInfoPtr lp, list;
  480.     int num_ext_event_classes;
  481.     XEventClass ListOfEventClass[3];
  482.     int tablet_press_class, tablet_release_class, tablet_motion_class;
  483.  
  484.  
  485.  
  486.     /* get a ptr to the list of all currently defined input devices */
  487.     list = (XDeviceInfoPtr) XListInputDevices(dpy, &ndevices);
  488.     if (!list) {
  489.         fprintf(stderr,"XlistInputDevices failed to generate a devices list\n");        exit(1);
  490.     }
  491.  
  492.    /* check out the /usr/people/4Dgifts/examples/devices/input/X/Xlist.c
  493.     *  program (which gets compiled into "xlist").  running it will list
  494.     *  all the currently available input devices on the machine xlist is
  495.     *  run on.  there is a LOT that should be studied in the "input" subtree.
  496.     */
  497.     for (lp=list, i=0; i<ndevices; lp++, i++) {
  498.         if (lp->use == IsXExtensionDevice && strcmp(lp->name,"tablet") == 0) {
  499.                 break;  /* found the right one--now save the ptr (lp) to it */
  500.         }
  501.     }
  502.     if (i == ndevices) {
  503.         fprintf(stderr, "\"tablet\" device not found\n");
  504.         exit(1);
  505.     }
  506.     tablet_device = XOpenDevice(dpy, lp->id);    /* open the Tablet device */
  507.     if (!tablet_device) {
  508.         fprintf(stderr, "XOpenDevice failedfor \"tablet\" device\n");
  509.         exit(1);
  510.     }
  511.     tablet_device_id = tablet_device->device_id;
  512.  
  513.    /* the following 3 macros determine the given event's type and class.
  514.     * each macro is passed the structure that describes the device from
  515.     * which input is desired.
  516.     */
  517.     DeviceButtonPress(tablet_device, tablet_press_type, tablet_press_class);
  518.     DeviceButtonRelease(tablet_device, tablet_release_type, tablet_release_class);
  519.     DeviceMotionNotify(tablet_device, tablet_motion_type, tablet_motion_class);
  520.  
  521.     ListOfEventClass[0]=tablet_press_class;
  522.     ListOfEventClass[1]=tablet_release_class;
  523.     ListOfEventClass[2]=tablet_motion_class;
  524.     num_ext_event_classes = 3;
  525.  
  526.    /* XSelectExtensionEvent requests the server to send events that match
  527.     * the events and devices described by the event list and that come
  528.     * from the requested window.
  529.     */
  530.     XSelectExtensionEvent(dpy, glwin, ListOfEventClass, num_ext_event_classes);
  531.  
  532. }
  533.  
  534.  
  535.  
  536. /*  draw the tablet's current line segment now that the event queue is drained
  537.  */
  538. static void drawcurrentline(void)
  539. {
  540.     struct lineElement *ptr;
  541. #ifdef GIVES_BROKEN_LINE__NOT_SURE_WHY
  542.     long vect[2];
  543.  
  544.     glIndexi(CYAN);
  545.  
  546.     glBegin(GL_LINES);                     /* draw our current line segment */
  547.  
  548.         for (ptr = lineLs.head; ptr->next != NULL; ptr = ptr->next) {
  549.             vect[0] = (long) (ptr->xy[0]*ratio);
  550.             vect[1] = (long) (ptr->xy[1]*ratio);
  551.             glVertex2i(vect[0], vect[1]);
  552.         }
  553.  
  554.     glEnd();
  555. #endif
  556.     int vect1[2];
  557.     int vect2[2];
  558.  
  559.  
  560.     glIndexi(CYAN);
  561.  
  562.     for (vect1[0] = (int) (lineLs.head->xy[0]*ratio),  /* initially get the */
  563.          vect1[1] = (int) (lineLs.head->xy[1]*ratio),  /* first vertex      */
  564.          ptr = lineLs.head->next; ptr->next != NULL; ptr = ptr->next) {
  565.  
  566.         vect2[0] = (int) (ptr->xy[0]*ratio);         /* get the next vertex */
  567.         vect2[1] = (int) (ptr->xy[1]*ratio);
  568.  
  569.         glBegin(GL_LINES);                 /* draw our current line segment */
  570.             glVertex2i(vect1[0], vect1[1]);
  571.             glVertex2i(vect2[0], vect2[1]);
  572.         glEnd();
  573.  
  574.         vect1[0] = vect2[0];          /* now save the last vertex into the  */
  575.         vect1[1] = vect2[1];          /* beginning of the next line segment */
  576.     }
  577. }
  578.  
  579.  
  580.  
  581. /*  makeframe -- Draw the tablet "background" in the GL window
  582.  */
  583. static void makeframe()
  584. {
  585.     glClearIndex((GLfloat) BLUE);
  586.     glClear(GL_COLOR_BUFFER_BIT);
  587.     glLoadIdentity();
  588.     gluOrtho2D(-0.5, xsize-0.5, -0.5, ysize-0.5);
  589.  
  590.     glIndexi(YELLOW);
  591.     glRasterPos2i(4, 5);
  592.     printString("Use left mouse button to quit.");
  593.  
  594.     glFlush();
  595. }
  596.  
  597.  
  598. /* makeRasterFont() and printString() are lifted out of font.c (lives in
  599.  * this same directory) as a replacement to the IrisGL charstr() function.
  600.  */
  601. GLuint base;
  602.  
  603. static void makeRasterFont(Display **dpy)
  604. {
  605.     XFontStruct *fontInfo;
  606.     Font id;
  607.     unsigned int first, last;
  608.  
  609.     fontInfo = XLoadQueryFont(*dpy,
  610.       "-sgi-screen-bold-r-normal--15-150-72-72-m-90-iso8859-1");
  611.     if (fontInfo == NULL) {
  612.         printf("no font found\n");
  613.         exit(0);
  614.     }
  615.     id = fontInfo->fid;
  616.     first = fontInfo->min_char_or_byte2;
  617.     last = fontInfo->max_char_or_byte2;
  618.     base = glGenLists(last+1);
  619.     if (base == 0) {
  620.         printf("out of display lists\n");
  621.         exit(0);
  622.     }
  623.     glXUseXFont(id, first, last-first+1, base+first);
  624. }
  625.  
  626. static void printString(char *s)
  627. {
  628.     glPushAttrib(GL_LIST_BIT);
  629.     glListBase(base);
  630.     glCallLists(strlen(s), GL_UNSIGNED_BYTE, (unsigned char *)s);
  631.     glPopAttrib();
  632. }
  633.  
  634.  
  635.  
  636. /*  clean_exit  --  Clean up before exiting 
  637.  */
  638. static void clean_exit(void)
  639. {
  640.     XCloseDisplay(dpy);
  641.     exit(0);
  642. }
  643.